package com.fadadianqi.logistics.search;

import com.fadadianqi.logistics.customer.model.Customer;
import com.fadadianqi.logistics.customer.model.Town;
import com.fadadianqi.logistics.customer.model.Village;
import com.fadadianqi.logistics.customer.service.CustomerService;
import com.fadadianqi.search.AbstractIndexService;
import com.fadadianqi.search.IndexPathHelper;
import com.fadadianqi.search.IndexPathHelper.IndexEnum;
import com.yeqiangwei.commons.util.DateTimeUtils;
import com.yeqiangwei.commons.util.Pagination;
import com.yeqiangwei.commons.util.StringHelper;
import com.yeqiangwei.commons.util.ValidatorHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.IndexWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("customerIndexService")
public class CustomerIndexService extends AbstractIndexService {

    private static final Log log = LogFactory.getLog(CustomerIndexService.class);

    private String newPath;

    private IndexPathHelper indexPathHelper = new IndexPathHelper(IndexEnum.CUSTOMER);

    public CustomerIndexService() {

    }

    @Override
    protected void changeIndexPath() {
        indexPathHelper.savePath(newPath);
    }

    @Override
    public String getCurrentIndexPath() {
        return indexPathHelper.getIndexPath();
    }

    @Override
    protected String getNewIndexPath() {
        newPath = indexPathHelper.createNewPath();
        return newPath;
    }

    protected void build(IndexWriter writer, boolean rebuild) throws Exception {
        synchronized (writer) {
            // 写操作保持同步
            int total = 0;
            if (rebuild) {
                total = customerService.countAll();
            } else {
                total = customerService.countAllNotIndexed();
            }
            int limit = 1000;
            int pages = total / limit;
            if (total % limit != 0) {
                pages++;
            }
            for (int page = 1; page <= pages; page++) {
                Pagination pagination = null;
                List<Customer> list = null;
                if (rebuild) {
                    pagination = new Pagination(page, limit);
                    list = customerService.findAll(pagination);
                } else {
                    pagination = new Pagination(1, limit);
                    list = customerService.findAllNotIndexed(pagination);
                }
                if (ValidatorHelper.isEmpty(list)) {
                    continue;
                }
                for (Customer customer : list) {
                    writer.addDocument(documentBuilder(customer));
                    customer.setIndexed(Boolean.TRUE);
                    customerService.updateCustomerIndexed(customer);
                }
            }
            writer.optimize();
            writer.close(true);
        }
    }

    protected Document documentBuilder(Object o) throws Exception {
        Customer customer = (Customer) o;
        Document doc = new Document();

        Field id = new Field(Customer.PROP_ID, customer.getId(), Store.YES, Index.NOT_ANALYZED);
        doc.add(id);

        Field name = new Field(Customer.PROP_NAME, customer.getName(), Store.YES, Index.ANALYZED);
        doc.add(name);

        String _townId = customer.getTownId();
        if (ValidatorHelper.isNotEmpty(_townId)) {
            Field townId = new Field(Customer.PROP_TOWN_ID, _townId, Store.YES, Index.ANALYZED);
            doc.add(townId);
            Town town = customerService.getTownById(_townId);
            if (town != null) {
                Field townName = new Field(Customer.PROP_TOWN_NAME, town.getName(), Store.YES, Index.ANALYZED);
                doc.add(townName);
            } else {
                log.warn("Town is not found (" + townId + ")");
            }
        }

        String _villageId = customer.getVillageId();
        if (ValidatorHelper.isNotEmpty(_villageId)) {
            Field villageId = new Field(Customer.PROP_VILLAGE_ID, _villageId, Store.YES, Index.ANALYZED);
            doc.add(villageId);
            Village village = customerService.getVillageById(_villageId);
            if (village != null) {
                Field villageName = new Field(Customer.PROP_VILLAGE_NAME, village.getName(), Store.YES, Index.ANALYZED);
                doc.add(villageName);
            } else {
                log.warn("Village is not found (" + villageId + ")");
            }
        }

        String str_pinyin = StringHelper.toPinyin(customer.getName());
        Field pinyin = new Field(Customer.PROP_PINYIN, str_pinyin, Store.YES, Index.ANALYZED);
        doc.add(pinyin);

        String str_initial = StringHelper.getInitial(customer.getName(), null);
        Field initial = new Field(Customer.PROP_INITIAL, str_initial, Store.YES, Index.ANALYZED);
        doc.add(initial);

        String str_tel = customer.getTel();
        if (str_tel != null) {
            Field tel = new Field(Customer.PROP_TEL, str_tel, Store.YES, Index.ANALYZED);
            doc.add(tel);
        }

        String str_mobile = customer.getMobile();
        if (str_mobile != null) {
            Field mobile = new Field(Customer.PROP_MOBILE, str_mobile, Store.YES, Index.ANALYZED);
            doc.add(mobile);
        }

        StringBuilder memoBuf = new StringBuilder();
        memoBuf.append(customer.getMemo());
        memoBuf.append(" ");
        memoBuf.append(super.toPinyinIndexContent(customer.getName()));
        Field memo = new Field(Customer.PROP_MEMO, memoBuf.toString(), Store.YES, Index.ANALYZED);
        doc.add(memo);

        long _addTime = DateTimeUtils.now();
        NumericField addTime = new NumericField(AbstractIndexService.ADD_TIME, Store.YES, Boolean.TRUE);
        addTime.setLongValue(_addTime);
        doc.add(addTime);

        log.debug("document: " + doc.toString());
        return doc;
    }

    private static Boolean IS_RUNNING = Boolean.FALSE;

    public synchronized boolean isRunning() {
        return IS_RUNNING;
    }

    protected synchronized void lock() {
        IS_RUNNING = true;
    }

    protected synchronized void unlock() {
        IS_RUNNING = false;
    }

    @Autowired
    private CustomerService customerService;

}
